<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>连连看游戏 - 修复版</title>
    <style>
        :root {
            --primary-color: #6a11cb;
            --secondary-color: #2575fc;
            --background-color: #f0f2f5;
            --icon-bg-color: #ffffff;
            --highlight-color: #ffeb3b;
            --text-color: #333;
            --border-radius: 12px;
            --shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
            --path-color: #ff5722; /* 连接线颜色 */
        }

        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }

        body {
            background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
        }

        .game-container {
            background-color: var(--background-color);
            border-radius: var(--border-radius);
            box-shadow: var(--shadow);
            width: 100%;
            max-width: 650px;
            padding: 25px;
            text-align: center;
            position: relative;
        }

        .game-title {
            color: var(--text-color);
            margin-bottom: 20px;
            font-size: 2.2rem;
            text-shadow: 1px 1px 2px rgba(0,0,0,0.1);
        }

        .game-info {
            display: flex;
            justify-content: space-between;
            margin-bottom: 20px;
            background-color: white;
            padding: 15px;
            border-radius: var(--border-radius);
            box-shadow: var(--shadow);
        }

        .info-item {
            font-size: 1.2rem;
            font-weight: bold;
        }

        .score { color: #4caf50; }
        .timer { color: #2196f3; }

        .controls {
            display: flex;
            justify-content: center;
            gap: 15px;
            margin-bottom: 20px;
        }

        button {
            padding: 12px 25px;
            border: none;
            border-radius: 50px;
            background: linear-gradient(to right, var(--primary-color), var(--secondary-color));
            color: white;
            font-size: 1.1rem;
            font-weight: bold;
            cursor: pointer;
            transition: transform 0.2s, box-shadow 0.2s;
            box-shadow: var(--shadow);
        }

        button:hover {
            transform: translateY(-2px);
            box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2);
        }

        button:active {
            transform: translateY(1px);
        }

        .board-wrapper {
            position: relative;
            display: inline-block;
            width: 100%;
        }

        .game-board {
            display: grid;
            gap: 12px;
            background-color: #e0e0e0;
            padding: 20px;
            border-radius: var(--border-radius);
            box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.1);
            position: relative;
            z-index: 2;
            margin: 0 auto;
        }

        .icon {
            width: 50px;
            height: 50px;
            background-color: var(--icon-bg-color);
            border-radius: calc(var(--border-radius) / 2);
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 1.8rem;
            font-weight: bold;
            cursor: pointer;
            transition: all 0.3s ease;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
            user-select: none;
        }

        .icon.selected {
            background-color: var(--highlight-color);
            transform: scale(0.95);
            box-shadow: 0 0 0 3px var(--secondary-color);
        }

        .icon.matched {
            visibility: hidden;
            opacity: 0;
        }

        @keyframes pop {
            0% { transform: scale(1); opacity: 1; }
            50% { transform: scale(1.2); opacity: 0.7; }
            100% { transform: scale(0); opacity: 0; }
        }

        .icon.matched.animating {
            animation: pop 0.5s forwards;
        }

        @keyframes pulse {
            0% { box-shadow: 0 0 0 0 rgba(37, 117, 252, 0.7); }
            70% { box-shadow: 0 0 0 10px rgba(37, 117, 252, 0); }
            100% { box-shadow: 0 0 0 0 rgba(37, 117, 252, 0); }
        }

        .icon.selected.animating {
            animation: pulse 1s infinite;
        }

        .path-overlay {
            position: absolute;
            top: 0;
            left: 0;
            pointer-events: none;
            z-index: 1;
            width: 100%;
            height: 100%;
        }

        .modal {
            display: none;
            position: fixed;
            z-index: 100;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            justify-content: center;
            align-items: center;
        }

        .modal-content {
            background-color: white;
            padding: 30px;
            border-radius: var(--border-radius);
            text-align: center;
            box-shadow: var(--shadow);
            max-width: 90%;
            width: 400px;
        }

        .modal h2 {
            margin-bottom: 20px;
            color: var(--text-color);
        }

        .modal p {
            font-size: 1.2rem;
            margin-bottom: 20px;
        }

        .status-bar {
            margin-top: 20px;
            padding: 10px;
            background: rgba(255, 255, 255, 0.9);
            border-radius: 8px;
            font-size: 1rem;
            color: #ff5722;
            font-weight: bold;
        }

        @media (max-width: 650px) {
            .game-container {
                padding: 15px;
            }
            .game-title {
                font-size: 1.8rem;
            }
            .info-item {
                font-size: 1rem;
            }
            .icon {
                width: 40px;
                height: 40px;
                font-size: 1.5rem;
            }
            .game-board {
                gap: 8px;
                padding: 15px;
            }
        }
    </style>
</head>
<body>

<div class="game-container">
    <h1 class="game-title">🐾 连连看 - 修复版 🐾</h1>
    
    <div class="game-info">
        <div class="info-item score">得分: <span id="score">0</span></div>
        <div class="info-item timer">时间: <span id="timer">120</span>s</div>
    </div>

    <div class="controls">
        <button id="restartBtn">🔄 重新开始</button>
        <button id="hintBtn">💡 提示</button>
    </div>

    <div class="board-wrapper">
        <div class="game-board" id="gameBoard"></div>
        <svg class="path-overlay" id="pathOverlay"></svg>
    </div>
    
    <div class="status-bar">
        连线问题已修复！现在可以显示消除路径，并支持棋盘外区域连线
    </div>
</div>

<div id="gameOverModal" class="modal">
    <div class="modal-content">
        <h2 id="modalTitle">游戏结束</h2>
        <p id="modalMessage">恭喜你完成了游戏!</p>
        <button id="closeModalBtn">确定</button>
    </div>
</div>

<script>
    document.addEventListener('DOMContentLoaded', () => {
        // --- 配置 ---
        const BOARD_SIZE = 8;
        const ICON_TYPES = 12;
        const INITIAL_TIME = 120;

        // --- 游戏状态 ---
        let board = [];
        let selectedIcons = [];
        let score = 0;
        let timeLeft = INITIAL_TIME;
        let timerInterval = null;
        let isProcessing = false;

        // --- DOM 元素 ---
        const gameBoard = document.getElementById('gameBoard');
        const pathOverlay = document.getElementById('pathOverlay');
        const scoreDisplay = document.getElementById('score');
        const timerDisplay = document.getElementById('timer');
        const restartBtn = document.getElementById('restartBtn');
        const hintBtn = document.getElementById('hintBtn');
        const gameOverModal = document.getElementById('gameOverModal');
        const modalTitle = document.getElementById('modalTitle');
        const modalMessage = document.getElementById('modalMessage');
        const closeModalBtn = document.getElementById('closeModalBtn');

        // --- 初始化 ---
        function initGame() {
            board = [];
            selectedIcons = [];
            score = 0;
            timeLeft = INITIAL_TIME;
            isProcessing = false;
            scoreDisplay.textContent = score;
            timerDisplay.textContent = timeLeft;

            gameBoard.innerHTML = '';
            pathOverlay.innerHTML = '';
            gameBoard.style.gridTemplateColumns = `repeat(${BOARD_SIZE}, 1fr)`;

            if (timerInterval) clearInterval(timerInterval);

            createBoardData();
            renderBoard();
            startTimer();
        }

        function createBoardData() {
            let icons = [];
            const totalIcons = BOARD_SIZE * BOARD_SIZE;
            for (let i = 0; i < totalIcons / 2; i++) {
                const iconType = i % ICON_TYPES;
                icons.push(iconType, iconType);
            }
            shuffleArray(icons);

            let index = 0;
            for (let row = 0; row < BOARD_SIZE; row++) {
                board[row] = [];
                for (let col = 0; col < BOARD_SIZE; col++) {
                    board[row][col] = {
                        type: icons[index],
                        isEmpty: false,
                        element: null
                    };
                    index++;
                }
            }
        }

        function renderBoard() {
            for (let row = 0; row < BOARD_SIZE; row++) {
                for (let col = 0; col < BOARD_SIZE; col++) {
                    const iconData = board[row][col];
                    if (!iconData.isEmpty) {
                        const iconElement = document.createElement('div');
                        iconElement.className = 'icon';
                        iconElement.textContent = String.fromCodePoint(0x1F600 + iconData.type);
                        iconElement.dataset.row = row;
                        iconElement.dataset.col = col;
                        
                        const hue = (iconData.type * 360) / ICON_TYPES;
                        iconElement.style.backgroundColor = `hsl(${hue}, 85%, 80%)`;
                        
                        iconElement.addEventListener('click', () => handleIconClick(row, col));
                        gameBoard.appendChild(iconElement);
                        iconData.element = iconElement;
                    }
                }
            }
        }

        // --- 游戏逻辑 ---
        function handleIconClick(row, col) {
            if (isProcessing || board[row][col].isEmpty) return;

            const iconElement = board[row][col].element;

            if (selectedIcons.length === 0) {
                selectedIcons.push({ row, col });
                iconElement.classList.add('selected', 'animating');
                return;
            }

            if (selectedIcons[0].row === row && selectedIcons[0].col === col) {
                selectedIcons.pop();
                iconElement.classList.remove('selected', 'animating');
                return;
            }

            selectedIcons.push({ row, col });
            iconElement.classList.add('selected');

            const firstIcon = board[selectedIcons[0].row][selectedIcons[0].col];
            const secondIcon = board[selectedIcons[1].row][selectedIcons[1].col];

            if (firstIcon.type === secondIcon.type) {
                const path = findPath(selectedIcons[0], selectedIcons[1]);
                if (path) {
                    isProcessing = true;
                    drawPath(path);

                    firstIcon.element.classList.add('animating');
                    secondIcon.element.classList.add('animating');

                    setTimeout(() => {
                        firstIcon.element.classList.add('matched');
                        secondIcon.element.classList.add('matched');
                        
                        firstIcon.isEmpty = true;
                        secondIcon.isEmpty = true;

                        score += 10;
                        scoreDisplay.textContent = score;

                        selectedIcons = [];
                        isProcessing = false;

                        if (isBoardEmpty()) {
                            endGame(true);
                        }
                    }, 600);
                } else {
                    firstIcon.element.classList.remove('selected', 'animating');
                    secondIcon.element.classList.remove('selected');
                    selectedIcons = [];
                }
            } else {
                firstIcon.element.classList.remove('selected', 'animating');
                secondIcon.element.classList.remove('selected');
                selectedIcons = [];
            }
        }

        /**
         * 查找两个图标之间的连接路径 (支持边缘和最多三次折线)
         * @param {Object} icon1 - 第一个图标的坐标 {row, col}
         * @param {Object} icon2 - 第二个图标的坐标 {row, col}
         * @returns {Array|null} 连接路径的坐标数组，如果无法连接则返回null
         */
        function findPath(icon1, icon2) {
            if (icon1.row === icon2.row && icon1.col === icon2.col) {
                return null;
            }
            
            if (board[icon1.row][icon1.col].type !== board[icon2.row][icon2.col].type) {
                return null;
            }

            // 创建扩展网格，包含棋盘外一圈
            const EXTENDED_SIZE = BOARD_SIZE + 2;
            // 初始化扩展网格，所有位置默认为可通行（0）
            const extendedGrid = Array(EXTENDED_SIZE).fill(null).map(() => Array(EXTENDED_SIZE).fill(0));

            // 填充原始棋盘数据到扩展网格，非空位置设置为障碍（1）
            for (let r = 0; r < BOARD_SIZE; r++) {
                for (let c = 0; c < BOARD_SIZE; c++) {
                    extendedGrid[r + 1][c + 1] = board[r][c].isEmpty ? 0 : 1;
                }
            }
            
            // 转换图标坐标到扩展网格
            const start = { row: icon1.row + 1, col: icon1.col + 1 };
            const end = { row: icon2.row + 1, col: icon2.col + 1 };
            
            // 确保起点和终点在扩展网格中标记为空
            extendedGrid[start.row][start.col] = 0;
            extendedGrid[end.row][end.col] = 0;

            // BFS队列和访问记录
            const queue = [];
            const visited = Array.from({ length: EXTENDED_SIZE }, () => 
                Array.from({ length: EXTENDED_SIZE }, () => 
                    Array(4).fill(Infinity)
                )
            );

            // 四个方向: 上, 右, 下, 左
            const directions = [[-1, 0], [0, 1], [1, 0], [0, -1]];

            // 初始化队列 - 从起点向四个方向出发
            for (let dir = 0; dir < 4; dir++) {
                const [dr, dc] = directions[dir];
                const nr = start.row + dr;
                const nc = start.col + dc;
                
                // 检查是否在扩展网格范围内
                if (nr >= 0 && nr < EXTENDED_SIZE && nc >= 0 && nc < EXTENDED_SIZE) {
                    if (extendedGrid[nr][nc] === 0) {
                        if (nr === end.row && nc === end.col) {
                            return [icon1, icon2];
                        }
                        queue.push({
                            r: nr,
                            c: nc,
                            dir: dir,
                            turns: 0,
                            path: [start]
                        });
                        visited[nr][nc][dir] = 0;
                    }
                }
            }

            // 也允许从起点本身开始搜索（处理直接相连的情况）
            queue.push({
                r: start.row,
                c: start.col,
                dir: -1,
                turns: -1,
                path: [start]
            });

            while (queue.length > 0) {
                const current = queue.shift();
                const currentPath = [...current.path, { r: current.r, c: current.c }];

                // 检查是否到达终点
                if (current.r === end.row && current.c === end.col) {
                    // 转换回原始坐标
                    return currentPath.map(p => ({
                        row: p.r - 1,
                        col: p.c - 1
                    }));
                }

                // 尝试所有可能的方向
                for (let newDir = 0; newDir < 4; newDir++) {
                    const [dr, dc] = directions[newDir];
                    const nr = current.r + dr;
                    const nc = current.c + dc;

                    // 检查是否在扩展网格范围内
                    if (nr < 0 || nr >= EXTENDED_SIZE || nc < 0 || nc >= EXTENDED_SIZE) {
                        continue;
                    }

                    // 检查是否可以通过
                    if (extendedGrid[nr][nc] !== 0) {
                        continue;
                    }

                    // 计算转弯次数
                    let newTurns = current.turns;
                    if (current.dir !== -1 && current.dir !== newDir) {
                        newTurns++;
                    } else if (current.dir === -1) {
                        newTurns = 0; // 初始方向
                    }

                    // 限制最多2次转弯
                    if (newTurns > 2) {
                        continue;
                    }

                    // 检查是否已经以更少或相同的转弯次数访问过
                    if (visited[nr][nc][newDir] <= newTurns) {
                        continue;
                    }

                    // 更新访问记录
                    visited[nr][nc][newDir] = newTurns;

                    // 添加到队列
                    queue.push({
                        r: nr,
                        c: nc,
                        dir: newDir,
                        turns: newTurns,
                        path: currentPath
                    });
                }
            }

            // 未找到路径
            return null;
        }

        /**
         * 在SVG覆盖层上绘制路径
         * @param {Array} path - 路径坐标数组 (原始棋盘坐标)
         */
        function drawPath(path) {
            if (!path || path.length < 2) return;

            // 清除之前的路径
            pathOverlay.innerHTML = '';

            // 获取棋盘容器（board-wrapper）的尺寸
            const boardWrapper = gameBoard.parentElement;
            const wrapperRect = boardWrapper.getBoundingClientRect();
            
            // 获取棋盘（game-board）的内边距
            const boardStyle = getComputedStyle(gameBoard);
            const paddingLeft = parseFloat(boardStyle.paddingLeft);
            const paddingTop = parseFloat(boardStyle.paddingTop);
            
            // 获取图标尺寸和间距
            const iconElements = gameBoard.querySelectorAll('.icon');
            if (iconElements.length === 0) return;
            
            const iconRect = iconElements[0].getBoundingClientRect();
            const iconSize = iconRect.width;
            const gap = parseFloat(getComputedStyle(gameBoard).gap) || 12;
            
            // 设置SVG尺寸以匹配棋盘容器
            pathOverlay.setAttribute('width', wrapperRect.width);
            pathOverlay.setAttribute('height', wrapperRect.height);
            
            // 计算第一个点（起点）
            let d = `M ${paddingLeft + (path[0].col * (iconSize + gap)) + (iconSize / 2)} 
                    ${paddingTop + (path[0].row * (iconSize + gap)) + (iconSize / 2)}`;
            
            // 添加路径上的其他点
            for (let i = 1; i < path.length; i++) {
                const x = paddingLeft + (path[i].col * (iconSize + gap)) + (iconSize / 2);
                const y = paddingTop + (path[i].row * (iconSize + gap)) + (iconSize / 2);
                d += ` L ${x} ${y}`;
            }

            const pathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');
            pathElement.setAttribute('d', d);
            pathElement.setAttribute('stroke', 'var(--path-color, #ff5722)');
            pathElement.setAttribute('stroke-width', '5');
            pathElement.setAttribute('fill', 'none');
            pathElement.setAttribute('stroke-linecap', 'round');
            pathElement.setAttribute('stroke-linejoin', 'round');
            
            // 动画效果
            const length = pathElement.getTotalLength();
            pathElement.style.strokeDasharray = length;
            pathElement.style.strokeDashoffset = length;
            pathElement.style.transition = 'stroke-dashoffset 0.5s ease-in-out';
            
            pathOverlay.appendChild(pathElement);

            // 触发动画
            requestAnimationFrame(() => {
                pathElement.style.strokeDashoffset = '0';
            });

            // 一段时间后清除路径
            setTimeout(() => {
                pathOverlay.innerHTML = '';
            }, 600);
        }

        function isBoardEmpty() {
            for (let row = 0; row < BOARD_SIZE; row++) {
                for (let col = 0; col < BOARD_SIZE; col++) {
                    if (!board[row][col].isEmpty) {
                        return false;
                    }
                }
            }
            return true;
        }

        function startTimer() {
            timerInterval = setInterval(() => {
                timeLeft--;
                timerDisplay.textContent = timeLeft;

                if (timeLeft <= 0) {
                    clearInterval(timerInterval);
                    endGame(false);
                }
            }, 1000);
        }

        function endGame(isWin) {
            clearInterval(timerInterval);
            modalTitle.textContent = isWin ? "🎉 恭喜! 🎉" : "⏰ 时间到!";
            modalMessage.textContent = isWin 
                ? `你赢了! 最终得分: ${score}` 
                : `游戏结束! 最终得分: ${score}`;
            gameOverModal.style.display = 'flex';
        }

        function shuffleArray(array) {
            for (let i = array.length - 1; i > 0; i--) {
                const j = Math.floor(Math.random() * (i + 1));
                [array[i], array[j]] = [array[j], array[i]];
            }
        }

        restartBtn.addEventListener('click', initGame);

        hintBtn.addEventListener('click', () => {
            if (isProcessing) return;
            for (let r1 = 0; r1 < BOARD_SIZE; r1++) {
                for (let c1 = 0; c1 < BOARD_SIZE; c1++) {
                    if (board[r1][c1].isEmpty) continue;
                    for (let r2 = 0; r2 < BOARD_SIZE; r2++) {
                        for (let c2 = 0; c2 < BOARD_SIZE; c2++) {
                            if (board[r2][c2].isEmpty || (r1 === r2 && c1 === c2)) continue;
                            if (board[r1][c1].type === board[r2][c2].type) {
                                if (findPath({row:r1, col:c1}, {row:r2, col:c2})) {
                                    board[r1][c1].element.style.boxShadow = '0 0 0 4px #ff9800';
                                    board[r2][c2].element.style.boxShadow = '0 0 0 4px #ff9800';
                                    setTimeout(() => {
                                        if (board[r1][c1].element && board[r2][c2].element) {
                                            board[r1][c1].element.style.boxShadow = '';
                                            board[r2][c2].element.style.boxShadow = '';
                                        }
                                    }, 1000);
                                    return;
                                }
                            }
                        }
                    }
                }
            }
            alert("暂时没有可消除的图标!");
        });

        closeModalBtn.addEventListener('click', () => {
            gameOverModal.style.display = 'none';
        });

        initGame();
    });
</script>

</body>
</html>